#ifndef TEST_GRAPHICS_RENDER_TEST_H
#	define TEST_GRAPHICS_RENDER_TEST_H

#include "test.h"

#include "renderer.h"
#include "renderwindow.h"
#include "hardwarebuffer.h"
#include "indexbuffer.h"
#include "vertexbuffer.h"
#include "shader.h"
#include "shaderhelpers.h"
#include "vertexshader.h"
#include "pixelshader.h"
#include "program.h"
#include "inputs/manager.h"
#include "inputs/command.h"

namespace dw {
	namespace graffiti {

class RenderWindow;

	} // namespace graffiti
} // namespace dw

namespace dw {
	namespace test {

class RenderTest
:	public Test
{
public : //! @name Types definitions
	//! @{
	typedef Test base;
	//! @}

public : //! @name Construction & Destruction
	//! @{
	RenderTest(const std::string& name) : base(name), m_isover(false) { ; }
	virtual ~RenderTest() { ; }
	//! @}

public : //! @name Commands
	//! @{
	virtual bool setup(dw::graffiti::RenderWindow* renderWindow)
	{
		if (base::setup())
		{
			dw::inputs::InputManager& inputManager = dw::inputs::InputManager::getInstance();
		
			m_exit.addCondition(dw::inputs::KeyStateCondition(OIS::KC_ESCAPE, dw::inputs::ButtonStateCondition::Pressed));

			m_mousePan.addCondition(dw::inputs::MouseButtonCondition(OIS::MB_Left, dw::inputs::ButtonStateCondition::Down));
			m_mousePan.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::Y, dw::inputs::MouseCursorSampler::Relative));

			m_mouseRotate.addCondition(dw::inputs::MouseButtonCondition(OIS::MB_Right, dw::inputs::ButtonStateCondition::Down));
			m_mouseRotate.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::X, dw::inputs::MouseCursorSampler::Relative));
			m_mouseRotate.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::Y, dw::inputs::MouseCursorSampler::Relative));

			inputManager.registerCommand(&m_exit);
			inputManager.registerCommand(&m_mousePan);
			inputManager.registerCommand(&m_mouseRotate);

			m_renderWindow = renderWindow;

			return true;
		}

		return false;
	}

	virtual bool render()
	{
		if (m_exit.isActive())
		{
			stop();
		}
		if (m_mousePan.isActive())
		{
			m_camTranslation.y += m_mousePan.getValue(0) * 0.2f;
		}
		if (m_mouseRotate.isActive())
		{
			m_camRotation.x += m_mouseRotate.getValue(0) * 0.5f;
			m_camRotation.y += m_mouseRotate.getValue(1) * 0.5f;
		}

		m_projection = glm::perspective(45.0f, float(m_renderWindow->getWidth()) / float(m_renderWindow->getHeight()), 0.1f, 100.f);

		glm::mat4 viewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -m_camTranslation.y));
		glm::mat4 viewRotateX = glm::rotate(viewTranslate, m_camRotation.y, glm::vec3(1.f, 0.f, 0.f));
		m_view = glm::rotate(viewRotateX, m_camRotation.x, glm::vec3(0.f, 1.f, 0.f));

		return true;
	}

	virtual bool teardown()
	{
		dw::inputs::InputManager& inputManager = dw::inputs::InputManager::getInstance();
		
		inputManager.unregisterCommand(&m_exit);
		inputManager.unregisterCommand(&m_mousePan);
		inputManager.unregisterCommand(&m_mouseRotate);

		return base::teardown();
	}
	//! @}

public : //! @name State
	//! @{
	bool isover() const { return m_isover; }
	void stop() { m_isover = true; }
	const glm::mat4& getViewMatrix() const { return m_view; }
	const glm::mat4& getProjectionMatrix() const { return m_projection; }
	//! @}

private : //! @name Data
	//! @{
	dw::graffiti::RenderWindow* m_renderWindow;
	bool m_isover;
	
	dw::inputs::InputCommand m_exit;
	dw::inputs::InputCommand m_mousePan;
	dw::inputs::InputCommand m_mouseRotate;

	glm::vec3 m_camTranslation;
	glm::vec3 m_camRotation;

	glm::mat4 m_projection;
	glm::mat4 m_view;
	//! @}
};

	} // namespace test
} // namespace dw

#endif // !TEST_GRAPHICS_RENDER_TEST_H
